home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / dev / cross / ava-0.2.5.lha / ava-0.2.5 / src / Lexer.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-23  |  6.4 KB  |  199 lines

  1. /*
  2.   Lexer.C
  3.  
  4.   Lexical Analyzer
  5.   Uros Platise, Feb 1998
  6. */
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "Symbol.h"
  11. #include "Global.h"
  12. #include "Error.h"
  13. #include "Reports.h"
  14.  
  15. /* The only Lexer Global Data Structure */
  16. TlxData lxdata;
  17. TlxData *lxP = &lxdata;
  18.  
  19. /* set source and open a file */
  20. TLexer::TLexer (){
  21.   lxdata.buf=lxdata.back_count=lxdata.lastCurPos=0;
  22.   lxdata.stick=lxdata.macro=false;
  23.   lxdata.type=TlxData::NEWLINE; /* first pass is new line pass - increments */
  24. }                               /* lineNumber counter */
  25.  
  26.  
  27. /* Macro Definitions */
  28. #define LX_C          lxdata.buf
  29. #define LX_NEXT       lexer.getnext()
  30.  
  31. #define LX_IS_SPECIAL (LX_C=='_')
  32. #define LX_IS_ALPHA   ((LX_C>='A' && LX_C<='Z')||(LX_C>='a' && LX_C<='z')||LX_IS_SPECIAL)
  33. #define LX_IS_BIN     (LX_C>='0' && LX_C<='1')
  34. #define LX_IS_DEC     (LX_C>='0' && LX_C<='9')
  35. #define LX_IS_HEX     (LX_IS_DEC||(LX_C>='A' &&LX_C<='F')||(LX_C>='a' &&LX_C<='f'))
  36. #define LX_IS_x       (LX_C=='x')
  37. #define LX_IS_b       (LX_C=='b')
  38. #define LX_IS_DOLLAR  (LX_C=='$')
  39. #define LX_IS_0       (LX_C=='0')
  40. #define LX_IS_QS      (LX_C=='"')
  41. #define LX_IS_PREPROC (LX_C=='#')
  42. #define LX_IS_SPACE   (LX_C==' ' || LX_C=='\t') /* or TAB */
  43. #define LX_IS_CONTROL (LX_C=='.' || LX_C==',' || LX_C=='{' || LX_C=='}' || LX_C=='(' || LX_C==')' || LX_C=='\\')
  44. #define LX_IS_MATH    (LX_C=='+' || LX_C=='-' || LX_C=='*' || LX_C=='/' || LX_C=='<' || LX_C=='>' || LX_C=='&' || LX_C=='|' || LX_C=='^' || LX_C=='=') /* LX_C=='!' is removed */
  45. #define LX_IS_NL      (LX_C=='\n')
  46. #define LX_IS_TRASH   (LX_C=='\r' /* || LX_C=='.' */ )
  47. #define LX_IS_EOL     (LX_C==0)
  48. #define LX_IS_TERM    (LX_IS_REM1||LX_IS_MATH||LX_IS_CONTROL||LX_IS_SPACE||LX_IS_TRASH||LX_IS_NL||LX_IS_EOL)
  49. #define LX_IS_LABEL   (LX_C==':')
  50. #define LX_IS_REM1    (LX_C==';')
  51.  
  52. #define LX_TOSTR      lxdata.string [strpos++]
  53.  
  54. /* Be sure what you are doing with the following lines.
  55.    There is no range cheking on these two operations */
  56. #define LX_STRBACK    strpos--;
  57. #define LX_C_BEFORE   lxdata.string [strpos-1]
  58.  
  59. inline void TLexer::getnext(){
  60.   lxdata.buf=preproc.getch();
  61. //  printf("got: %d (%c)\n", lxdata.buf, lxdata.buf);
  62.   if (strlen(lxdata.string)==(LX_STRLEN-1)){
  63.     throw generic_error("Lexer buffer is too small."
  64.                         " Increase LX_STRLEN in Lexer.h");}
  65. }
  66.  
  67. /* push back old character and clear current buffer */
  68. void TLexer::flush(){
  69.   lxdata.buf=0;     /* clear buffer so it will be reread next time */
  70.   preproc.putbackch();    /* give current ch back to the owner ... */
  71. }
  72.  
  73. /* returns TlxData::EOF if eof is reached otherwise lxdata is updated. */
  74. int TLexer::__gettoken(){
  75.   if (lxdata.back_count>0){lxdata.back_count--;return lxdata.type;}  
  76.   if (LX_IS_EOL){
  77.     getnext();if (LX_IS_EOL){return (lxdata.type=TlxData::THEEND);}}
  78.   
  79.   int strpos; long aux;
  80.   
  81.   lxdata.stick = true;
  82.   /* go state machine */
  83.   while (lxdata.buf != 0){
  84.     strpos=aux=0;
  85.     lxdata.string [0] = 0;
  86.     lxdata.lval = 0;
  87.     lxdata.macro = false;
  88.   
  89.     if (LX_IS_SPACE){lxdata.stick=false; LX_NEXT; continue;}
  90.     if (LX_IS_TRASH){lxdata.stick=false; LX_NEXT; continue;}
  91.     if (LX_IS_ALPHA){
  92.       preproc.mark();
  93.       while (LX_IS_ALPHA || LX_IS_DEC){LX_TOSTR = LX_C; LX_NEXT;}
  94.       LX_TOSTR = 0;
  95.       if (LX_IS_LABEL){LX_NEXT; return lxdata.type=TlxData::LABEL;}
  96.       if (!LX_IS_TERM){throw lexer_error (LX_C);}
  97.       return lxdata.type=TlxData::STRING;
  98.     }
  99.     if (LX_IS_QS){
  100.       LX_NEXT; /* skip " character */
  101.       while (!(LX_IS_QS || LX_IS_EOL)){LX_TOSTR = LX_C; LX_NEXT;}
  102.       if (LX_IS_EOL){throw lexer_error("Incorrectly terminated string");}
  103.       preproc.mark();      
  104.       LX_TOSTR = 0; LX_NEXT; /* skip " character */
  105.       return (lxdata.type = TlxData::QSTRING);
  106.     }
  107.     if (LX_IS_PREPROC){
  108.       preproc.mark();    
  109.       LX_NEXT; return (lxdata.type = TlxData::PREPROC);
  110.     }
  111.     if (LX_IS_CONTROL){ 
  112.       preproc.mark();
  113.       LX_TOSTR = LX_C; LX_TOSTR = 0; LX_NEXT;
  114.       return (lxdata.type = TlxData::CONTROL);
  115.     }
  116.     if (LX_IS_REM1){    /* standard assembler remarks starting with ; */
  117.       while (!(LX_IS_NL || LX_IS_EOL)){LX_NEXT;}
  118.       lxdata.stick=false;
  119.       continue; /* start at the beginning */
  120.     }
  121.     if (LX_IS_MATH){
  122.       preproc.mark();
  123.       while (LX_IS_MATH){
  124.         LX_TOSTR = LX_C; LX_NEXT;
  125.     /* standard C remarks starting with / and * and closing reversibly */
  126.     if (LX_C_BEFORE=='/' && LX_C=='*'){
  127.       if (strpos==0){lxdata.stick=false;}
  128.       LX_STRBACK;    /* remove last character: / */
  129.       char ch;    /* buffer for last character */
  130.       do{ch=LX_C; LX_NEXT;
  131.       }while(!LX_IS_EOL&& !(ch=='*'&&LX_C=='/'));
  132.       /* continue with parsing the equation */
  133.       LX_NEXT; /* remove / ch */
  134.     }
  135.       }
  136.       /* if there was not just C comment, go out with MATH */
  137.       if (strpos>0){LX_TOSTR = 0;return (lxdata.type = TlxData::MATH);}
  138.       continue; /* start at the beginning */
  139.     }
  140.     if (LX_IS_DEC || LX_IS_DOLLAR){
  141.       preproc.mark();
  142.       lxdata.lval = 0;
  143.       if (LX_IS_0){
  144.         LX_NEXT;
  145.     if (LX_IS_x){goto hex;}
  146.     else if (LX_IS_b){
  147.       LX_NEXT;
  148.           while (LX_IS_BIN){ 
  149.         lxdata.lval <<= 1; lxdata.lval |= LX_C - '0'; LX_NEXT;}
  150.     }else{goto dec;}
  151.       } 
  152.       else if (LX_IS_DOLLAR){ /* hex */
  153. hex:    LX_NEXT;
  154.     while (LX_IS_HEX){
  155.       if (LX_IS_DEC){aux = LX_C - '0';}
  156.       else if (LX_C > 'F'){aux = LX_C - 'a' + 10;}
  157.       else {aux = LX_C - 'A' + 10;}
  158.       lxdata.lval <<= 4; lxdata.lval |= aux; LX_NEXT;
  159.     }    
  160.       }else{ /* decimal */
  161. dec:    while (LX_IS_DEC){
  162.       lxdata.lval *= 10; lxdata.lval += LX_C - '0'; LX_NEXT;
  163.     }
  164.       }
  165.       if (!LX_IS_TERM){throw lexer_error (LX_C);}
  166.       sprintf(lxP->string, "$%lx", lxP->lval); /* convert to hex... */
  167.       return (lxdata.type = TlxData::LVAL);
  168.     }
  169.     if (LX_IS_NL){LX_NEXT; return lxdata.type=TlxData::NEWLINE;}
  170.  
  171.     /* if none of above options are incorrect, then it must be an error */
  172.     throw lexer_error (LX_C);
  173.   }
  174.   return (lxdata.type=TlxData::THEEND); /* eof */
  175. }
  176.  
  177. int TLexer::_gettoken(){
  178.   __gettoken();
  179. //  printf("%ld:(%d,%s)\n",preproc.line(),lxP->type,lxP->string);  
  180.   return lxP->type;
  181. }
  182. int TLexer::gettoken(){
  183.   int maxCount = 128;
  184.   _gettoken();  
  185.   while (symbol.replaceWithMacro()==1){
  186.     _gettoken();    /* if string is replaced, flush old one */
  187.     lxP->macro=true;    /* set flag, that original source is macro */    
  188.     if (maxCount--==0){throw syntax_error("Recursive symbols ... ");}
  189.   }
  190.   return lxP->type;
  191. }
  192.  
  193. void TLexer::Unroll(){
  194.   while(lxP->type!=TlxData::NEWLINE && lxP->type!=TlxData::THEEND){
  195.     gettoken();
  196.   }
  197. }
  198.  
  199.